#include "camera.h"
#include "encode_h264_aac.h"
#include <opencv2/opencv.hpp>
#include <pthread.h>
#include <semaphore.h>
#include <fstream>
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <ctime>
#include <alsa/asoundlib.h>
#include <queue>
#include <vector>
#include <atomic>
#include <sys/stat.h>

// 全局变量
uint8_t *buf_yuv[max_buffer] = {NULL};
uint8_t *buf_yuv420[max_buffer] = {NULL};
int yuv_byteused[max_buffer];
cv::Mat yuv_frame[max_buffer];

pthread_t thread_id_capture_decoder;
pthread_t thread_id_encode_video;
pthread_t thread_id_encode_audio;
pthread_t thread_id_save_av;

sem_t sem_buf_empty;
sem_t sem_buf_fill;
sem_t sem_packet_available;

// 配置参数
uint32_t camera_width = 640;
uint32_t camera_height = 480;
uint32_t video_fps = 25;
uint32_t video_bitrate = 2000000;

uint32_t audio_sample_rate = 44100;
uint32_t audio_channels = 2;
uint32_t audio_bitrate = 192000;

CAMERA camera_test(camera_width, camera_height);
ENCODE_H264_AAC encode_video_test;
ENCODE_H264_AAC encode_audio_test;

const char* record_path = "/home/orangepi/save_video/";
char h264_filename[256];
char aac_filename[256];
char output_filename[256];

bool stop = false;
bool is_recording = true;

std::mutex save_video_mutex_;
std::mutex sync_queue_mutex;
std::queue<AVPacket*> save_video_queue_;
std::queue<AVPacket*> save_audio_queue_;
std::ofstream video_file;
std::ofstream audio_file;

// 音频录制相关
snd_pcm_t *capture_handle;
int record_seconds = 0; // 0表示持续录制直到手动停止

// 函数声明
void *thread_capture_decoder(void *argv);
void *thread_encode_video(void *argv);
void *thread_encode_audio(void *argv);
void *thread_save_av(void *argv);
void cleanup_resources();
bool init_audio_capture();

//开始时间
void init_timestamp();
//获取当前时间
int64_t get_current_timestamp();
/*******************************************同步************************************************/
struct compare  {
    bool operator()(const AVPacket* a,const AVPacket* b) {
        return a->pts > b->pts; // 定义最小堆
    }
};
//定义优先队列 元素类型为 AVPacket包
std::priority_queue<AVPacket* , std::vector<AVPacket*>, compare> sync_packet_queue;
std::mutex video_queue_mutex;

std::chrono::steady_clock::time_point recording_start_time;
std::atomic<int64_t> current_timestamp_ms{0};
struct video_audio {
    uint8_t* data;        //音视频数据
    int64_t timestamp_ms; //相对于开始时间的毫秒时间戳
    int size;             //视频表示大小，音频表示样本数
    bool video_or_audio;  //true:video  false:audio
};

std::queue<video_audio> video_frame_queue;
std::condition_variable video_queue_cv;
/*******************************************同步************************************************/


int main() {
    // 生成带时间戳的文件名
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    
    snprintf(h264_filename, sizeof(h264_filename), "%srecord_%04d%02d%02d_%02d%02d%02d.h264", 
             record_path, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
             t->tm_hour, t->tm_min, t->tm_sec);
    
    snprintf(aac_filename, sizeof(aac_filename), "%srecord_%04d%02d%02d_%02d%02d%02d.aac", 
             record_path, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
             t->tm_hour, t->tm_min, t->tm_sec);
    
    snprintf(output_filename, sizeof(output_filename), "%srecord_%04d%02d%02d_%02d%02d%02d.mp4", 
             record_path, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
             t->tm_hour, t->tm_min, t->tm_sec);

    // 初始化摄像头
    if (!camera_test.camera_init(camera_width, camera_height)) {
        std::cerr << "摄像头初始化失败" << std::endl;
        return -1;
    }

    // 初始化视频编码器
    if (!encode_video_test.init_h264(camera_width, camera_height, video_fps, video_bitrate)) {
        std::cerr << "视频编码器初始化失败" << std::endl;
        return -1;
    }

    // 初始化音频采集
    if (!init_audio_capture()) {
        std::cerr << "音频采集初始化失败" << std::endl;
        return -1;
    }

    // 初始化音频编码器
    if (!encode_audio_test.init_aac(audio_sample_rate, audio_channels, audio_bitrate)) {
        std::cerr << "音频编码器初始化失败" << std::endl;
        return -1;
    }

    camera_test.camera_on();

    // 初始化信号量
    sem_init(&sem_buf_empty, 0, max_buffer);
    sem_init(&sem_buf_fill, 0, 0);
    sem_init(&sem_packet_available, 0, 0);

    // 打开输出文件
    video_file.open(h264_filename, std::ios::binary);
    audio_file.open(aac_filename, std::ios::binary);
    
    if (!video_file.is_open() || !audio_file.is_open()) {
        std::cerr << "无法创建输出文件" << std::endl;
        stop = true;
    }

    // 创建线程
    pthread_create(&thread_id_capture_decoder, NULL, thread_capture_decoder, NULL);
    pthread_create(&thread_id_encode_video, NULL, thread_encode_video, NULL);
    pthread_create(&thread_id_encode_audio, NULL, thread_encode_audio, NULL);
    pthread_create(&thread_id_save_av, NULL, thread_save_av, NULL);

    // 设置非阻塞输入
    int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
    
    std::cout << "按 'r' + Enter 停止录制..." << std::endl;
    std::cout << "正在录制视频和音频..." << std::endl;

    // 主循环
    while (!stop) {
        char buf_cmd[30] = {0};
        ssize_t bytes_read = read(STDIN_FILENO, buf_cmd, sizeof(buf_cmd)-1);
        
        if (bytes_read > 0) {
            buf_cmd[bytes_read] = '\0';
            if (strstr(buf_cmd, "r") != nullptr) {
                std::cout << "停止录制..." << std::endl;
                is_recording = false;
                stop = true;
                break;
            }
        }
        
        usleep(100000);
    }

    // 等待线程结束
    pthread_join(thread_id_capture_decoder, NULL);
    pthread_join(thread_id_encode_video, NULL);
    pthread_join(thread_id_encode_audio, NULL);
    pthread_join(thread_id_save_av, NULL);

    // 清理资源
    cleanup_resources();

    std::cout << "文件已保存: " << std::endl;
    std::cout << "  视频: " << h264_filename << std::endl;
    std::cout << "  音频: " << aac_filename << std::endl;

    // 这里可以添加使用ffmpeg合并音视频的代码
    std::string cmd = "ffmpeg -i " + std::string(h264_filename) + " -i " + 
                     std::string(aac_filename) + " -c copy " + std::string(output_filename);
    system(cmd.c_str());

    return 0;
}


bool init_audio_capture() {
    int err;
    
    if ((err = snd_pcm_open(&capture_handle, "plughw:2,0", SND_PCM_STREAM_CAPTURE, 0)) < 0) {
        printf("无法打开PCM设备 %s", snd_strerror(err));
        return false;
    }

    snd_pcm_hw_params_t *capture_params;
    snd_pcm_hw_params_alloca(&capture_params);
    snd_pcm_hw_params_any(capture_handle, capture_params);

    snd_pcm_hw_params_set_access(capture_handle, capture_params, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(capture_handle, capture_params, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_channels(capture_handle, capture_params, audio_channels);
    snd_pcm_hw_params_set_rate_near(capture_handle, capture_params, &audio_sample_rate, 0);

    snd_pcm_uframes_t buffer_size = 8192;
    snd_pcm_hw_params_set_buffer_size_near(capture_handle, capture_params, &buffer_size);

    //每次采集的样本帧数 1024 ,因为是立体声(channels=2 所以实际是2048个样本 每个样本2字节  每次就采集4096B)
    snd_pcm_uframes_t period_size = 1024;
    snd_pcm_hw_params_set_period_size_near(capture_handle, capture_params, &period_size, 0);

    if ((err = snd_pcm_hw_params(capture_handle, capture_params)) < 0) {
        printf("无法设置硬件参数 %s \n", snd_strerror(err));
        return false;
    }

    return true;
}

//捕获摄像头数据
void *thread_capture_decoder(void *argv) {
    init_timestamp();

    while (!stop) {
        for (int i = 0; i < max_buffer; i++) {
            sem_wait(&sem_buf_empty);

            buf_yuv[i] = camera_test.camera_take_one(&yuv_byteused[i]);
            //获取当前时间与程序开始时间的差值
            int64_t timestamp_ms = get_current_timestamp();

            if (buf_yuv420[i] == NULL) {
                buf_yuv420[i] = new uint8_t[camera_width * camera_height * 3 / 2];
            }
            camera_test.convertYUYVtoYUV420(buf_yuv[i], buf_yuv420[i], camera_width, camera_height);
            video_audio video_frame;
            video_frame.data           = buf_yuv420[i];
            video_frame.timestamp_ms   = timestamp_ms;
            video_frame.size           = camera_width * camera_height * 3 / 2; 
            video_frame.video_or_audio = true;

            {   
                std::lock_guard<std::mutex> lock(sync_queue_mutex);
                video_frame_queue.push(video_frame);
            }

            //条件变量 通知
            video_queue_cv.notify_one();

            sem_post(&sem_buf_fill);
        }   
    }
    return nullptr;
}

//编码H264帧
void *thread_encode_video(void *argv) {
    while (!stop) {
        video_audio video_frame;

        {
            std::unique_lock<std::mutex> lock(video_queue_mutex);
            //在最多等待 100 毫秒的时间内，检查队列 video_frame_queue 是否非空或者停止标志 stop 是否被设置
            //如果条件满足，线程将继续执行；如果在 100 毫秒内条件没有满足，线程将从 wait_for 函数返回。
    
            video_queue_cv.wait_for(lock, std::chrono::milliseconds(100), 
                [&]{ return !video_frame_queue.empty() || stop; });
            
            if (stop) break;
            if (video_frame_queue.empty()) continue;
            //从视频捕获队列中取一帧
            video_frame = video_frame_queue.front();
            video_frame_queue.pop();
        }

        encode_video_test.encodeH264Frame(video_frame.data, [inter_timestamp_ms = video_frame.timestamp_ms](AVPacket* pkt) {
            // 设置视频包的时间戳
            AVRational time_base = {1,1000}; //毫秒时间基
            // a 根据时间基b 转化为c 
            pkt->pts = av_rescale_q(inter_timestamp_ms, time_base, encode_video_test.get_time_base());
            pkt->dts = pkt->pts;
            pkt->stream_index = 0;
            
            {
                std::lock_guard<std::mutex> lock(sync_queue_mutex);
                AVPacket* cloned_pkt = av_packet_clone(pkt);
                sync_packet_queue.push(cloned_pkt);
            }
            
            sem_post(&sem_packet_available);
        });

        sem_post(&sem_buf_empty);
    }
    
    // 刷新编码器
    encode_video_test.flushEncoder([](AVPacket* pkt) {
        std::lock_guard<std::mutex> lock(sync_queue_mutex);
        AVPacket* cloned_pkt = av_packet_clone(pkt);
        sync_packet_queue.push(cloned_pkt);
        sem_post(&sem_packet_available);
    });

    return nullptr;
}

//编码AAC帧
void *thread_encode_audio(void *argv) {
    int frame_size = encode_audio_test.getFrameSize();
    //                                        1024  * 2 * 2 2048个样本，每个样本2B，总大小4096B
    uint16_t *pcm_buffer = (uint16_t *)malloc(frame_size * audio_channels * sizeof(uint16_t));
    
    if (!pcm_buffer) {
        std::cerr << "音频缓冲区分配失败" << std::endl;
        return nullptr;
    }

    while (!stop) {
        // 读取PCM数据
        snd_pcm_sframes_t frames_read = snd_pcm_readi(capture_handle, pcm_buffer, frame_size);
        
        if (frames_read == -EPIPE) {
            snd_pcm_prepare(capture_handle);
            continue;
        } else if (frames_read < 0) {
            std::cerr << "音频读取错误: " << snd_strerror(frames_read) << std::endl;
            break;
        }
        int64_t timestamp_ms = get_current_timestamp();

        // 编码音频帧
        encode_audio_test.encodeAACFrame(pcm_buffer, frames_read, [inter_timestamp_ms = timestamp_ms](AVPacket* pkt) {

            // 设置音频包的时间戳
            AVRational time_base = {1, 1000}; // 毫秒时间基
            pkt->pts = av_rescale_q(inter_timestamp_ms, time_base, 
                                  encode_audio_test.get_time_base());
            pkt->dts = pkt->pts;
            pkt->stream_index = 1;
             
            std::lock_guard<std::mutex> lock(sync_queue_mutex);
            AVPacket* cloned_pkt = av_packet_clone(pkt);
            sync_packet_queue.push(cloned_pkt);
            sem_post(&sem_packet_available);
        });
    }

    // 刷新编码器
    encode_audio_test.flushEncoder([](AVPacket* pkt) {
        std::lock_guard<std::mutex> lock(sync_queue_mutex);
        AVPacket* cloned_pkt = av_packet_clone(pkt);
        sync_packet_queue.push(cloned_pkt);
        sem_post(&sem_packet_available);
    });

    free(pcm_buffer);
    return nullptr;
}

//保存为h264和aac文件
void *thread_save_av(void *argv) {
    std::cout << "1" << std::endl;
    while (!stop || !sync_packet_queue.empty() ) {
        // 等待有包可用
        if (sem_trywait(&sem_packet_available) != 0) {
            usleep(1000);
            continue;
        }
        std::cout << "2" << std::endl;

        std::vector<AVPacket*> packets_to_write;

        {
            std::lock_guard<std::mutex> lock(sync_queue_mutex);
            std::cout << "3" << std::endl;

            // 每次取一批包按顺序处理
            while (!sync_packet_queue.empty() ) {
                AVPacket* pkt = sync_packet_queue.top();
                sync_packet_queue.pop();
                packets_to_write.push_back(pkt);
                std::cout << "4" << std::endl;
            }
        }

        // 按PTS顺序写入包
        for (AVPacket* pkt : packets_to_write) {
            std::cout << "5" << std::endl;

            if (pkt->stream_index == 0) { // 视频流
                if (video_file.is_open() && pkt->size > 0) {  //uint8_t * data
                    video_file.write(reinterpret_cast<char*>(pkt->data), pkt->size);  
                    std::cout << "写入视频包 PTS: " << pkt->pts 
                              << ", 大小: " << pkt->size << " 字节" << std::endl;
                }
            } else if (pkt->stream_index == 1)  { // 音频流
                if (audio_file.is_open() && pkt->size > 0) {
                    // 添加ADTS头
                    uint8_t adts_buffer[pkt->size + 7];
                    encode_audio_test.add_adts_header(adts_buffer, pkt->size, 2, 
                                                     audio_sample_rate, audio_channels);
                    memcpy(adts_buffer + 7, pkt->data, pkt->size);
                    audio_file.write(reinterpret_cast<char*>(adts_buffer), pkt->size + 7);
                    std::cout << "写入音频包 PTS: " << pkt->pts 
                              << ", 大小: " << pkt->size << " 字节" << std::endl;
                }
            }
            av_packet_free(&pkt);
        }

        usleep(1000); // 短暂休眠避免CPU占用过高
    }
    return nullptr;
}

void init_timestamp(){
    recording_start_time = std::chrono::steady_clock::now();
}

int64_t get_current_timestamp(){
    auto now = std::chrono::steady_clock::now();
    return std::chrono::duration_cast<std::chrono::milliseconds>(
        now - recording_start_time).count();
}


void cleanup_resources() {
    camera_test.camera_off();
    camera_test.camera_close();
    
    snd_pcm_close(capture_handle);
    
    encode_video_test.cleanup();
    encode_audio_test.cleanup();

    if (video_file.is_open()) video_file.close();
    if (audio_file.is_open()) audio_file.close();

    sem_destroy(&sem_buf_empty);
    sem_destroy(&sem_buf_fill);
    sem_destroy(&sem_packet_available);
    sem_destroy(&sem_packet_available);

    for (int i = 0; i < max_buffer; i++) {
        if (buf_yuv420[i] != NULL) {
            delete[] buf_yuv420[i];
            buf_yuv420[i] = NULL;
        }
    }

    // 清理队列
    while (!save_video_queue_.empty()) {
        AVPacket* pkt = save_video_queue_.front();
        av_packet_free(&pkt);
        save_video_queue_.pop();
    }

    while (!save_audio_queue_.empty()) {
        AVPacket* pkt = save_audio_queue_.front();
        av_packet_free(&pkt);
        save_audio_queue_.pop();
    }
}